package cn.datawin.common.state;

import cn.datawin.common.state.entity.BaseBasket;
import cn.datawin.common.state.template.SimpleTemplate;
import cn.datawin.common.state.template.condition.ConditionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.squirrelframework.foundation.fsm.*;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.datawin.common.state.constant.State.END;
import static cn.datawin.common.state.constant.State.INIT;

/**
 * @Author: huanyayun
 * @Date: 2021/10/27 15:19
 */
public class StateMachineUtil {
    private static Logger logger = LoggerFactory.getLogger(StateMachineUtil.class);

    /**
     * from状态=>to状态，触发条件是 event(from, to) 即为from + "=>" + to
     * @param from
     * @param to
     * @param builder
     */
    public static void external(String from, String to, UntypedStateMachineBuilder builder) {
        builder.externalTransition().from(from).to(to).on(event(from, to));
    }

    /**
     * 进入指定状态触发若干actions
     * @param stateName 触发状态
     * @param builder 状态机构造器
     * @param actions 动作集合
     */
    public static void onEntry(String stateName, UntypedStateMachineBuilder builder ,List<UntypedAnonymousAction> actions) {
        builder.onEntry(stateName).perform(actions);
    }

    /**
     * 统一格式的event生成方法
     * @param from
     * @param to
     * @return
     */
    public static String event(String from, String to) {
        return from + "=>" + to;
    }

    /**
     * 进入指定状态触发指定方法
     * @param stateName
     * @param builder
     * @param funcName
     */
    public static void onEntryCallMethod(String stateName, UntypedStateMachineBuilder builder,String funcName) {
        builder.onEntry(stateName).callMethod(funcName);//onEntry
    }

    /**
     * 离开指定状态触发指定方法
     * @param stateName
     * @param builder
     * @param funcName
     */
    public static void onExitCallMethod(String stateName, UntypedStateMachineBuilder builder,String funcName) {
        builder.onExit(stateName).callMethod(funcName);
    }

    /**
     * 内部状态中 from=>to 触发event是exec 满足条件 condition
     * @param from
     * @param to
     * @param exec
     * @param condition
     * @param builder
     */
    public static void localTransition(String from,String to,String exec,Condition<Object> condition,UntypedStateMachineBuilder builder){
        builder.localTransition().from(from).to(to).on(exec).when(condition);
    }

    /**
     * 内部状态中 from=>to 触发event是exec 无需满足任何条件
     * @param from
     * @param to
     * @param builder
     */
    public static void localTransition(String from,String to,UntypedStateMachineBuilder builder){
        builder.localTransition().from(from).to(to).on(event(from,to));
    }

    /**
     * 初始化状态机构造器 模式1
     * @param stateMachineClazz 状态机基类
     * @param simpleTemplateList 简单模板集合
     * @return
     */
    public static UntypedStateMachineBuilder initBuilder(Class<? extends UntypedStateMachine> stateMachineClazz,  List<SimpleTemplate> simpleTemplateList) {
        long t1 = System.currentTimeMillis();
        UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(stateMachineClazz);
        external(INIT,simpleTemplateList.get(0).getStateName(),builder);
        for (int i = 0; i < simpleTemplateList.size(); i++) {
            int size = simpleTemplateList.size();
            SimpleTemplate currentTemplate = simpleTemplateList.get(i);
            if(size>1&&i!=size-1){
                SimpleTemplate nextTemplate = simpleTemplateList.get(i + 1);
                external(currentTemplate.getStateName(),nextTemplate.getStateName(),builder);
            }
            currentTemplate.execActions(builder);
        }
        long t2 = System.currentTimeMillis();
        logger.debug("{}.initBuilder耗时 {}ms",stateMachineClazz.getName(),(t2-t1));
        return builder;
    }

    /**
     * 反射获取指定包名下的UntypedAnonymousAction对象
     * @param packageName
     * @param classNamePrefix 类名前缀
     * @return
     */
    public static UntypedAnonymousAction getStableActionByName(String packageName,String classNamePrefix) {
        Object obj = null;
        try {
            Class<?> cls; // 取得Class对象
            Constructor<?> cons;
            // Abnormal+Action
            String className = classNamePrefix.substring(0, 1).toUpperCase() + classNamePrefix.substring(1) + "Action";

            cls = Class.forName(packageName+"."+className);
            cons = cls.getConstructor();
            obj= cons.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj==null?null: ((UntypedAnonymousAction) obj);
    }

    /**
     *
     * 初始化状态机构造器 模式2
     * @param stateMachineClazz 状态机基类
     * @param conditionTemplateList 带内部流程的模板集合
     * @return
     */
    public static UntypedStateMachineBuilder initInruleBuilder(Class<? extends UntypedStateMachine> stateMachineClazz,  List<ConditionTemplate> conditionTemplateList) {
        UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(stateMachineClazz);
        external(INIT, conditionTemplateList.get(0).getStateName(),builder);
        int size = conditionTemplateList.size();
        for (int i = 0; i < conditionTemplateList.size(); i++) {
            ConditionTemplate currentTemplate = conditionTemplateList.get(i);
            if(size>1&&i!=size-1){
                ConditionTemplate nextTemplate = conditionTemplateList.get(i + 1);
                external(currentTemplate.getStateName(),nextTemplate.getStateName(),builder);
            }
            currentTemplate.execActions(builder);
        }
        external(END, INIT,builder);
        return builder;
    }

    public static List<UntypedAnonymousAction> actionToList (UntypedAnonymousAction action){
      return  new ArrayList<>(Collections.singletonList(action));
    }

    public static boolean isState(String curVoiceName) {
        Pattern pattern=Pattern.compile("Z\\d+");
        Matcher matcher = pattern.matcher(curVoiceName);
        return matcher.matches();
    }

	public static void createAndStartMachine(
			Class<? extends UntypedStateMachine> machineClass,
			Object initialState,
			BaseBasket basket,
			SimpleTemplate... templates
			) {
		try {

			List<SimpleTemplate> simpleTemplateList = new ArrayList<>(Arrays.asList(templates));
			UntypedStateMachineBuilder builder = StateMachineUtil.initBuilder(machineClass, simpleTemplateList);
			UntypedStateMachine fsm = builder.newStateMachine(initialState);
			List<String> collect = simpleTemplateList.stream().map(SimpleTemplate::getStateName).collect(Collectors.toList());
			basket.setLines(collect);
			fsm.start();
			fsm.fire(event(INIT, collect.get(0)), basket);
			fsm.terminate();
		} catch (Exception e) {
			logger.error("InputDealMachineService---exception",e);
		}
	}
}
